#!/usr/bin/env python3
"""
OpenBMC D-Bus接口分析工具主程序

从OpenBMC代码仓库提取D-Bus接口信息并导出到Excel表格
"""

import os
import sys
import argparse
import logging
from pathlib import Path
from datetime import datetime
from colorama import init, Fore, Style

# 添加当前目录到Python路径
current_dir = Path(__file__).parent
sys.path.insert(0, str(current_dir))

from interface_collector import InterfaceCollector
from excel_exporter import ExcelExporter
from data_structures import AnalysisResult

# 初始化colorama
init()


def setup_logging(log_level: str = "INFO", log_file: str = None):
    """
    设置日志配置
    
    Args:
        log_level: 日志级别
        log_file: 日志文件路径
    """
    log_format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
    
    # 配置根日志器
    logging.basicConfig(
        level=getattr(logging, log_level.upper()),
        format=log_format,
        handlers=[]
    )
    
    # 控制台处理器
    console_handler = logging.StreamHandler()
    console_handler.setFormatter(logging.Formatter(log_format))
    logging.getLogger().addHandler(console_handler)
    
    # 文件处理器
    if log_file:
        file_handler = logging.FileHandler(log_file, encoding='utf-8')
        file_handler.setFormatter(logging.Formatter(log_format))
        logging.getLogger().addHandler(file_handler)


def print_banner():
    """打印程序横幅"""
    banner = f"""
{Fore.CYAN}╔═══════════════════════════════════════════════════════════════╗
║                OpenBMC D-Bus接口分析工具                      ║
║                                                               ║
║  功能: 从OpenBMC代码仓库提取D-Bus接口信息并导出到Excel         ║
║  作者: openUBMC社区                                      ║
║  版本: v1.0.0                                                 ║
╚═══════════════════════════════════════════════════════════════╝{Style.RESET_ALL}
"""
    print(banner)


def validate_paths(args):
    """
    验证输入路径
    
    Args:
        args: 命令行参数
        
    Returns:
        bool: 验证是否通过
    """
    # 检查OpenBMC路径
    if args.openbmc_path:
        openbmc_path = Path(args.openbmc_path)
        if not openbmc_path.exists():
            print(f"{Fore.RED}错误: OpenBMC路径不存在: {args.openbmc_path}{Style.RESET_ALL}")
            return False
    
    # 检查phosphor-dbus-interfaces路径
    phosphor_path = Path(args.phosphor_path)
    if not phosphor_path.exists():
        print(f"{Fore.RED}错误: phosphor-dbus-interfaces路径不存在: {args.phosphor_path}{Style.RESET_ALL}")
        return False
    
    # 检查输出目录
    output_path = Path(args.output)
    output_dir = output_path.parent
    if not output_dir.exists():
        try:
            output_dir.mkdir(parents=True, exist_ok=True)
            print(f"{Fore.YELLOW}创建输出目录: {output_dir}{Style.RESET_ALL}")
        except Exception as e:
            print(f"{Fore.RED}错误: 无法创建输出目录 {output_dir}: {e}{Style.RESET_ALL}")
            return False
    
    return True


def analyze_interfaces(args) -> AnalysisResult:
    """
    分析D-Bus接口
    
    Args:
        args: 命令行参数
        
    Returns:
        分析结果
    """
    logger = logging.getLogger(__name__)
    collector = InterfaceCollector()
    
    print(f"{Fore.GREEN}开始分析D-Bus接口...{Style.RESET_ALL}")
    
    # 收集phosphor-dbus-interfaces
    print(f"{Fore.BLUE}正在扫描 phosphor-dbus-interfaces...{Style.RESET_ALL}")
    result = collector.collect_phosphor_interfaces(args.phosphor_path)
    
    # 如果指定了OpenBMC路径，还要扫描其他仓库
    if args.openbmc_path:
        openbmc_path = Path(args.openbmc_path)
        
        # 查找其他相关仓库
        repo_patterns = [
            'bmcweb*',
            'phosphor-host-ipmid*',
            'phosphor-inventory-manager*',
            'phosphor-logging*',
            'phosphor-user-management*',
            'phosphor-time-manager*'
        ]
        
        additional_repos = {}
        for pattern in repo_patterns:
            matching_dirs = list(openbmc_path.glob(pattern))
            for repo_dir in matching_dirs:
                if repo_dir.is_dir():
                    additional_repos[repo_dir.name] = str(repo_dir)
        
        if additional_repos:
            print(f"{Fore.BLUE}找到额外的仓库: {', '.join(additional_repos.keys())}{Style.RESET_ALL}")
            additional_result = collector.collect_from_multiple_repos(additional_repos)
            
            # 合并结果
            for interface in additional_result.interfaces:
                result.add_interface(interface)
            result.errors.extend(additional_result.errors)
            result.warnings.extend(additional_result.warnings)
    
    # 过滤公共接口
    if args.public_only:
        print(f"{Fore.BLUE}过滤非公共接口...{Style.RESET_ALL}")
        public_interfaces = [i for i in result.interfaces if i.is_public]
        
        # 创建新的结果对象
        filtered_result = AnalysisResult()
        for interface in public_interfaces:
            filtered_result.add_interface(interface)
        filtered_result.errors = result.errors
        filtered_result.warnings = result.warnings
        
        result = filtered_result
    
    # 验证接口数据
    if args.validate:
        print(f"{Fore.BLUE}验证接口数据完整性...{Style.RESET_ALL}")
        validation_errors = collector.validate_interfaces(result.interfaces)
        result.errors.extend(validation_errors)
    
    return result


def export_results(result: AnalysisResult, args):
    """
    导出分析结果
    
    Args:
        result: 分析结果
        args: 命令行参数
    """
    print(f"{Fore.GREEN}导出分析结果...{Style.RESET_ALL}")
    
    exporter = ExcelExporter()
    success = exporter.export_to_excel(result, args.output)
    
    if success:
        print(f"{Fore.GREEN}✓ Excel文件导出成功: {args.output}{Style.RESET_ALL}")
        
        # 显示文件大小
        file_size = Path(args.output).stat().st_size / 1024 / 1024
        print(f"{Fore.CYAN}文件大小: {file_size:.2f} MB{Style.RESET_ALL}")
        
    else:
        print(f"{Fore.RED}✗ Excel文件导出失败{Style.RESET_ALL}")


def print_summary(result: AnalysisResult):
    """
    打印分析摘要
    
    Args:
        result: 分析结果
    """
    print(f"\n{Fore.GREEN}═══ 分析摘要 ═══{Style.RESET_ALL}")
    print(f"{Fore.CYAN}总接口数:{Style.RESET_ALL} {result.total_interfaces}")
    print(f"{Fore.CYAN}公共接口数:{Style.RESET_ALL} {result.public_interfaces}")
    print(f"{Fore.CYAN}总方法数:{Style.RESET_ALL} {result.total_methods}")
    print(f"{Fore.CYAN}总属性数:{Style.RESET_ALL} {result.total_properties}")
    print(f"{Fore.CYAN}总信号数:{Style.RESET_ALL} {result.total_signals}")
    
    # 显示分类统计
    if result.categories:
        print(f"\n{Fore.GREEN}接口分类统计:{Style.RESET_ALL}")
        for category, count in sorted(result.categories.items(), key=lambda x: x[1], reverse=True):
            print(f"  {category}: {count}")
    
    # 显示命名空间统计
    if result.namespaces:
        print(f"\n{Fore.GREEN}命名空间统计:{Style.RESET_ALL}")
        for namespace, count in sorted(result.namespaces.items(), key=lambda x: x[1], reverse=True):
            print(f"  {namespace}: {count}")
    
    # 显示错误和警告
    if result.errors:
        print(f"\n{Fore.RED}错误 ({len(result.errors)}):{Style.RESET_ALL}")
        for error in result.errors[:5]:  # 只显示前5个
            print(f"  {Fore.RED}• {error}{Style.RESET_ALL}")
        if len(result.errors) > 5:
            print(f"  {Fore.RED}... 还有 {len(result.errors) - 5} 个错误{Style.RESET_ALL}")
    
    if result.warnings:
        print(f"\n{Fore.YELLOW}警告 ({len(result.warnings)}):{Style.RESET_ALL}")
        for warning in result.warnings[:5]:  # 只显示前5个
            print(f"  {Fore.YELLOW}• {warning}{Style.RESET_ALL}")
        if len(result.warnings) > 5:
            print(f"  {Fore.YELLOW}... 还有 {len(result.warnings) - 5} 个警告{Style.RESET_ALL}")


def main():
    """主函数"""
    print_banner()
    
    # 解析命令行参数
    parser = argparse.ArgumentParser(
        description='OpenBMC D-Bus接口分析工具',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
示例用法:
  %(prog)s --phosphor-path ./phosphor-dbus-interfaces --output interfaces.xlsx
  %(prog)s --openbmc-path ./openbmc --phosphor-path ./phosphor-dbus-interfaces --output all_interfaces.xlsx --public-only
  %(prog)s --phosphor-path ./phosphor-dbus-interfaces --output debug.xlsx --log-level DEBUG --validate
        """
    )
    
    parser.add_argument(
        '--openbmc-path', 
        type=str,
        help='OpenBMC主仓库路径（可选，用于扫描额外的仓库）'
    )
    
    parser.add_argument(
        '--phosphor-path',
        type=str,
        required=True,
        help='phosphor-dbus-interfaces仓库路径'
    )
    
    parser.add_argument(
        '--output',
        type=str,
        default=f'openbmc_dbus_interfaces_{datetime.now().strftime("%Y%m%d_%H%M%S")}.xlsx',
        help='输出Excel文件路径（默认：带时间戳的文件名）'
    )
    
    parser.add_argument(
        '--public-only',
        action='store_true',
        help='仅导出公共接口（排除厂商特定接口）'
    )
    
    parser.add_argument(
        '--validate',
        action='store_true',
        help='验证接口数据完整性'
    )
    
    parser.add_argument(
        '--log-level',
        choices=['DEBUG', 'INFO', 'WARNING', 'ERROR'],
        default='INFO',
        help='日志级别（默认：INFO）'
    )
    
    parser.add_argument(
        '--log-file',
        type=str,
        help='日志文件路径（可选）'
    )
    
    args = parser.parse_args()
    
    # 设置日志
    setup_logging(args.log_level, args.log_file)
    logger = logging.getLogger(__name__)
    
    try:
        # 验证路径
        if not validate_paths(args):
            sys.exit(1)
        
        # 分析接口
        start_time = datetime.now()
        result = analyze_interfaces(args)
        analysis_time = datetime.now() - start_time
        
        # 导出结果
        export_results(result, args)
        
        # 打印摘要
        print_summary(result)
        
        print(f"\n{Fore.GREEN}✓ 分析完成，耗时: {analysis_time.total_seconds():.2f} 秒{Style.RESET_ALL}")
        
        # 退出码
        if result.errors:
            print(f"\n{Fore.RED}注意: 分析过程中发现错误，请检查日志{Style.RESET_ALL}")
            sys.exit(1)
        elif result.warnings:
            print(f"\n{Fore.YELLOW}注意: 分析过程中发现警告，请检查输出{Style.RESET_ALL}")
            sys.exit(0)
        else:
            sys.exit(0)
            
    except KeyboardInterrupt:
        print(f"\n{Fore.YELLOW}用户取消操作{Style.RESET_ALL}")
        sys.exit(130)
    except Exception as e:
        logger.exception("程序执行过程中发生未知错误")
        print(f"\n{Fore.RED}错误: {e}{Style.RESET_ALL}")
        sys.exit(1)


if __name__ == '__main__':
    main()
